﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Csla;
using System.Data;
using System.IO;
using System.Web;
using Csla.Data;
using Csla.Validation;
using System.Data.Common;
using System.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Data;
using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;
using System.Threading;

namespace Asah.SiteWorx.Commerce
{
    [Serializable()]
    public class Order : Csla.BusinessBase<Order>
    {

        #region Business Methods

        private int _id = 0;
        private OrderStatus _status = OrderStatus.Pending;
        private OrderItems _orderItems = OrderItems.NewOrderItems();
        private ShipTo _shipTo = ShipTo.NewShipTo();
        private BillTo _billTo = BillTo.NewBillTo();
        private PaymentDetail _paymentDetail = PaymentDetail.NewPaymentDetail();
        private Membership.User _createdBy;
        private SmartDate _createdDate;
        private Membership.User _lastUpdatedBy;
        private SmartDate _lastUpdatedDate;

        [System.ComponentModel.DataObjectField(true,true)]
        public int ID
        {
            get
            {
                CanReadProperty("ID", true);
                return _id;
            }
        }

        public OrderStatus Status
        {
            get
            {
                CanReadProperty("Status", true);
                return _status;
            }
            set
            {
                CanWriteProperty("Status", true);
                if (_status != value)
                {
                    _status = value;
                    PropertyHasChanged("Status");
                }
            }
        }

        public OrderItems OrderItems
        {
            get
            {
                return _orderItems;
            }
        }

        public ShipTo ShipTo
        {
            get
            {
                return _shipTo;
            }
        }

        public BillTo BillTo
        {
            get
            {
                return _billTo;
            }
        }

        public PaymentDetail PaymentDetail
        {
            get
            {
                return _paymentDetail;
            }
        }

        public decimal Total
        {
            get
            { 
                decimal grandTotal = 0;
                foreach (OrderItem item in _orderItems)
                {
                    grandTotal += item.Total;
                }
                return grandTotal;
            }
        }
       
        public Membership.User CreatedBy
        {
            get
            {
                CanReadProperty("CreatedBy", true);
                return _createdBy;
            }
        }

        public string CreatedDate
        {
            get
            {
                CanReadProperty("CreatedDate", true);
                return _createdDate.ToString("g");
            }
        }

        public Membership.User LastUpdatedBy
        {
            get
            {
                CanReadProperty("LastUpdatedBy", true);
                return _lastUpdatedBy;
            }
        }

        public string LastUpdatedDate
        {
            get
            {
                CanReadProperty("LastUpdatedDate", true);
                return _lastUpdatedDate.ToString("g");
            }
        }

        public override bool IsDirty
        {
            get
            {
                return base.IsDirty || _orderItems.IsDirty || _shipTo.IsDirty || _billTo.IsDirty || _paymentDetail.IsDirty;
            }
        }

        public override bool IsValid
        {
            get
            {
                return base.IsValid && _orderItems.IsValid && _shipTo.IsValid && _billTo.IsValid && _paymentDetail.IsValid;
            }
        }

        protected override object GetIdValue()
        {
            return _id;
        }

        #endregion

        #region Validation Rules

        protected override void AddBusinessRules()
        {
            // add BusinessRules here
        }

        #endregion

        #region Authorization Rules

        protected override void AddAuthorizationRules()
        {
            // add AuthorizationRules here
        }

        public static bool CanAddOrder()
        {
            return true;
        }

        public static bool CanGetOrder()
        {
            return true;
        }

        public static bool CanDeleteOrder()
        {
            return Thread.CurrentPrincipal.IsInRole("Administrator");
        }

        public static bool CanEditOrder()
        {
            return Thread.CurrentPrincipal.IsInRole("Administrator");
        }

        #endregion

        #region Factory Methods

        public static Order NewOrder()
        {
            if (!CanAddOrder())
            {
                throw new System.Security.SecurityException("User not authorized to add an order.");
            }
            return DataPortal.Create<Order>(null);
        }

        public static Order GetOrder(int id)
        {
            if (!CanGetOrder())
            {
                throw new System.Security.SecurityException("User not authorized to view a order.");
            }
            return DataPortal.Fetch<Order>(new Criteria(id));
        }

        public static void DeniedOrder(int id)
        {
            if (!CanEditOrder())
            {
                throw new System.Security.SecurityException("User not authorized to deny an order.");
            }
            DataPortal.Execute<DeniedOrderCommand>(new DeniedOrderCommand(id));
        }

        public static void ProcessedOrder(int id)
        {
            if (!CanEditOrder())
            {
                throw new System.Security.SecurityException("User not authorized to process an order.");
            }
            DataPortal.Execute<ProcessedOrderCommand>(new ProcessedOrderCommand(id));
        }

        public override Order Save()
        {
            if (IsNew && !CanAddOrder())
            {
                throw new System.Security.SecurityException("User not authorized to create an order.");
            }
            return base.Save();
        }

        private Order()
        {
            // require use of factory methods
        }
       
        #endregion

        #region Data Access

        [Serializable()]
        private class Criteria
        {
            private int _id;

            public int ID
            {
                get
                {
                    return _id;
                }
            }

            public Criteria(int id)
            {
                _id = id;
            }
        }

        [RunLocal()]
        private void DataPortal_Create(Criteria criteria)
        {
            // add initial data to the object here
            // check all the validation rules
            ValidationRules.CheckRules();
        }

        private void DataPortal_Fetch(Criteria criteria)
        {
            Database db = DatabaseFactory.CreateDatabase("SiteWorxCommerce");
            DbCommand dbCommand = db.GetStoredProcCommand("aspnet_Orders_GetOrder");
            db.AddInParameter(dbCommand, "ApplicationId", DbType.Guid, Site.GetSite().ApplicationId);
            db.AddInParameter(dbCommand, "OrderId", DbType.Int32, criteria.ID);
            try
            {
                using (var dr = new SafeDataReader(db.ExecuteReader(dbCommand)))
                {
                    if (dr.Read())
                    {
                        _id = dr.GetInt32("OrderId");
                        _status = (OrderStatus)dr.GetInt32("Status");
                        _createdBy = Membership.User.GetUser(dr.GetGuid("CreatedBy"));
                        _createdDate = dr.GetSmartDate("CreatedDate");
                        _lastUpdatedBy = Membership.User.GetUser(dr.GetGuid("LastUpdatedBy"));
                        _lastUpdatedDate = dr.GetSmartDate("LastUpdatedDate");

                        dr.NextResult();
                        _orderItems = OrderItems.GetOrderItems(dr);

                        dr.NextResult();
                        _shipTo = ShipTo.GetShipTo(dr);

                        dr.NextResult();
                        _billTo = BillTo.GetBillTo(dr);

                        dr.NextResult();
                        _paymentDetail = PaymentDetail.GetPaymentDetail(dr);
                    }
                }
            }
            catch (Exception ex)
            {
                bool rethrow = ExceptionPolicy.HandleException(ex, "Data Access Layer Policy");
                if (rethrow)
                {
                    throw;
                }
            }
        }

        protected override void DataPortal_Insert()
        {
            Database db = DatabaseFactory.CreateDatabase("SiteWorxCommerce");
            DbCommand dbCommand = db.GetStoredProcCommand("aspnet_Orders_AddOrder");
            db.AddInParameter(dbCommand, "ApplicationId", DbType.Guid, Site.GetSite().ApplicationId);
            db.AddInParameter(dbCommand, "Status", DbType.Int32, _status);
            db.AddInParameter(dbCommand, "CreatedBy", DbType.Guid, Membership.User.GetUser(Thread.CurrentPrincipal.Identity.Name).ID);
            db.AddInParameter(dbCommand, "CreatedDate", DbType.DateTime, DateTime.Now);


            try
            {
                _id = int.Parse(db.ExecuteScalar(dbCommand).ToString());
                dbCommand.Dispose();
            }
            catch (Exception ex)
            {
                bool rethrow = ExceptionPolicy.HandleException(ex, "Data Access Layer Policy");
                if (rethrow)
                {
                    throw;
                }
            }

            _orderItems.Insert(this);
            _shipTo.Insert(this);
            _billTo.Insert(this);
            _paymentDetail.Insert(this);
        }

        #endregion

        #region DenyOrderCommand

        [Serializable()]
        private class DeniedOrderCommand : CommandBase
        {
            private int _orderId;

            public DeniedOrderCommand(int orderId)
            {
                _orderId = orderId;
            }

            protected override void DataPortal_Execute()
            {
                Database db = DatabaseFactory.CreateDatabase("SiteWorxCommerce");
                DbCommand dbCommand = db.GetStoredProcCommand("aspnet_Orders_UpdateStatus");
                db.AddInParameter(dbCommand, "ApplicationId", DbType.Guid, Site.GetSite().ApplicationId);
                db.AddInParameter(dbCommand, "OrderId", DbType.Int32, _orderId);
                db.AddInParameter(dbCommand, "Status", DbType.Int32, OrderStatus.Denied);
                db.AddInParameter(dbCommand, "LastUpdatedBy", DbType.Guid, Membership.User.GetUser(Thread.CurrentPrincipal.Identity.Name).ID);
                db.AddInParameter(dbCommand, "LastUpdatedDate", DbType.DateTime, DateTime.Now);

                try
                {
                    db.ExecuteNonQuery(dbCommand);
                    dbCommand.Dispose();
                }
                catch (Exception ex)
                {
                    bool rethrow = ExceptionPolicy.HandleException(ex, "Data Access Layer Policy");
                    if (rethrow)
                    {
                        throw;
                    }
                }
            }
        }
        #endregion

        #region ProcessedOrderCommand

        [Serializable()]
        private class ProcessedOrderCommand : CommandBase
        {
            private int _orderId;

            public ProcessedOrderCommand(int orderId)
            {
                _orderId = orderId;
            }

            protected override void DataPortal_Execute()
            {
                Database db = DatabaseFactory.CreateDatabase("SiteWorxCommerce");
                DbCommand dbCommand = db.GetStoredProcCommand("aspnet_Orders_UpdateStatus");
                db.AddInParameter(dbCommand, "ApplicationId", DbType.Guid, Site.GetSite().ApplicationId);
                db.AddInParameter(dbCommand, "OrderId", DbType.Int32, _orderId);
                db.AddInParameter(dbCommand, "Status", DbType.Int32, OrderStatus.Processed);
                db.AddInParameter(dbCommand, "LastUpdatedBy", DbType.Guid, Membership.User.GetUser(Thread.CurrentPrincipal.Identity.Name).ID);
                db.AddInParameter(dbCommand, "LastUpdatedDate", DbType.DateTime, DateTime.Now);

                try
                {
                    db.ExecuteNonQuery(dbCommand);
                    dbCommand.Dispose();
                }
                catch (Exception ex)
                {
                    bool rethrow = ExceptionPolicy.HandleException(ex, "Data Access Layer Policy");
                    if (rethrow)
                    {
                        throw;
                    }
                }
            }
        }
        #endregion

    }
}
